﻿using System;
using System.Data;
using System.Xml.Linq;

namespace YawetagLib.Data.Xml
{
    public class Connection : IDbConnection
    {
        public Connection(string filePath)
        {
            Database = filePath;
        }

        public IDbTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            LockDocument();

            return new Transaction(this);
        }

        public IDbTransaction BeginTransaction()
        {
            return BeginTransaction(IsolationLevel.Unspecified);
        }

        internal void ReleaseTransaction(bool isCommit)
        {
            UnlockDocument(!isCommit);
            if (isCommit) { Submit(); }
        }

        public void ChangeDatabase(string filePath)
        {
            if (State != ConnectionState.Open) { Database = filePath; }
        }

        public IDbCommand CreateCommand()
        {
            throw new NotImplementedException();
        }

        public virtual void Open()
        {
            State = ConnectionState.Connecting;
            Document = XDocument.Load(Database);

            State = ConnectionState.Open;
        }

        public virtual void Close()
        {
            State = ConnectionState.Closed;
        }

        public virtual void Submit()
        {
            if (!IsDocumentLocked) { Document.Save(Database); }
        }

        public XDocument GetDocument()
        {
            if (State != ConnectionState.Open) { Open(); }

            return Document;
        }

        private void LockDocument()
        {
            LockedDocument = Document;
            Document = new XDocument(LockedDocument);
        }

        private void UnlockDocument(bool isRollback)
        {
            if (IsDocumentLocked && isRollback) { Document = LockedDocument; }
            LockedDocument = null;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                if (disposing)
                {
                    ManagedResourceCleanup();
                }
                UnmanagedResourceCleanup();
                IsDisposed = true;
            }
        }

        protected virtual void ManagedResourceCleanup()
        {
            Close();
        }

        protected virtual void UnmanagedResourceCleanup()
        {
        }

        ~Connection()
        {
            Dispose(false);
        }

        public string ConnectionString { get; set; }
        public int ConnectionTimeout { get; set; }
        public string Database { get; private set; }
        public ConnectionState State { get; private set; }

        private XDocument Document { get; set; }
        private XDocument LockedDocument { get; set; }

        private bool IsDocumentLocked
        {
            get { return LockedDocument != null; }
        }

        private bool IsDisposed { get; set; }
    }
}
